package node_category

import (
	"gitee.com/theegg/go-brick/app/model"
	"gitee.com/theegg/go-brick/app/model/content/nodes"
	"gitee.com/theegg/go-brick/app/model/user/users"
	"gitee.com/theegg/go-brick/app/service/app"
)

// 查询参数
type NodeCategoryQueryParams struct {
	PageSize  string `form:"page_size" json:"page_size"  binding:"gte=0,lte=100" label:"每页数量"`
	PageIndex string `form:"page_index" json:"page_index"  binding:"gte=0,lte=99999" label:"当前页数"`
	Title     string `form:"title" json:"title"  binding:"omitempty,min=2,max=24" label:"标题"`
	Slug      string `form:"slug" json:"slug"  binding:"omitempty,min=2,max=16" label:"标识"`
}

// 添加参数
type NodeCategoryAddParams struct {
	Id    int64  `form:"id" binding:"" label:"ID"`
	Title string `form:"title"  binding:"required,min=2,max=24" label:"标题"`
	Pid   int64  `form:"pid" binding:"" label:"上级ID"`
	Slug  string `form:"slug"  binding:"required,min=2,max=24" label:"标识"`
}

// 返回的数据结构 == select
type CategorySelectData struct {
	Id       int64                 `json:"id"`
	Label    string                `json:"label"`
	Children []*CategorySelectData `json:"children"`
}

// 分页获取所有数据
// @param params map 参数
// @return interface{}, error
func GetDataList(params map[string]interface{}) (map[string]interface{}, error) {
	returnData := make(map[string]interface{}, 0)

	queryParams, errBuild := model.BuildAdminQueryParam(params)
	if errBuild != nil {
		return nil, app.NewError(errBuild)
	}

	query := app.Db().Desc("node_category.id").
		Limit(queryParams.Limit, queryParams.Offset)

	// query title
	if _, ok := queryParams.Params["title"]; ok && queryParams.Params["title"] != "" {
		query.Where("node_category.title like ?", "%"+queryParams.Params["title"].(string)+"%")
	}

	// query slug
	if _, ok := queryParams.Params["slug"]; ok && queryParams.Params["slug"] != "" {
		query.Where("node_category.slug like ?", "%"+queryParams.Params["slug"].(string)+"%")
	}

	data := make([]NodeCategory, 0)

	// 求总条数
	total, err := query.FindAndCount(&data)
	if err != nil {
		return nil, app.NewError(err)
	}

	returnData["data"] = data
	returnData["total"] = total

	return returnData, nil
}

// @title AddOrUpdate
// @description 更新或者添加 @todo 应该用事务!!!!
func (nc *NodeCategory) AddOrUpdate(params NodeCategoryAddParams) (*NodeCategory, error) {
	// 分类
	var pItem *NodeCategory
	var errPid error
	sort := 0
	if params.Pid > 0 {
		pItem, errPid = GetItemById(params.Pid)
		if errPid != nil {
			return nil, app.NewError(errPid)
		}
		sort = pItem.Sort + 1
	}

	// slug不能重复
	if IsUniqueFieldValueExist("slug", params.Slug) {
		return nil, app.NewError("对不起, 分类的标识不能重复")
	}

	nc.Title = params.Title
	if params.Pid == -1 {
		nc.Pid = 0
	} else {
		nc.Pid = params.Pid
	}
	nc.Slug = params.Slug
	if nc != nil && nc.Id > 0 {
		affected, errUpdate := app.Db().ID(nc.Id).Update(nc)

		if errUpdate != nil {
			return nil, app.NewError(errUpdate)
		}

		if affected != 1 {
			return nil, app.NewError("更新错误")
		}
	} else {
		nc.Sort = sort
		nc.Status = true
		affected, errInsert := app.Db().Insert(nc)
		if errInsert != nil {
			return nil, app.NewError(errInsert)
		}

		if affected != 1 {
			return nil, app.NewError("新增内容分类错误(0x001)")
		}
	}

	// 刷新缓存
	FlushCacheByTag()
	return nc, nil
}

// @title DeleteItem
// @description 删除一个分类:　1. 删除所有的下级 2. 移动所有的node到默认分类下
func (nc NodeCategory) DeleteItem() error {
	// 获取所有的下级IDS
	allChildren, errChild := nc.GetChildItem()
	if errChild != nil {
		return app.NewError(errChild)
	}

	childIds := make([]int64, 0)
	for id, _ := range allChildren {
		childIds = append(childIds, id)
	}

	// 获取默认ID
	defaultItem := new(NodeCategory)
	has, errGetDefault := app.Db().Get(defaultItem)
	if errGetDefault != nil {
		return app.NewError(errGetDefault)
	}

	if !has {
		return app.NewError("对不起, 您没有默认分类, 请联系管理员")
	}

	// 开启事务
	session := app.Db().NewSession()
	defer session.Close()

	// 删除分类
	deleteCategory := new(NodeCategory)
	_, errDelete := session.In("id", childIds).Delete(deleteCategory)
	if errDelete != nil {
		session.Rollback()
		return app.NewError(errDelete)
	}

	// 移动内容到默认分类下
	_, errMove := session.Table(new(nodes.Nodes)).In("cat_id", childIds).Cols("cat_id").Update(map[string]interface{}{"cat_id": defaultItem.Id})
	if errMove != nil {
		session.Rollback()
		return app.NewError(errMove)
	}

	// 提交
	errCommit := session.Commit()
	if errCommit != nil {
		return app.NewError(errCommit)
	}

	return nil
}

// 获取所有的下级
func (nc NodeCategory) GetChildItem() (map[int64]*NodeCategory, error) {
	items := make(map[int64]*NodeCategory)
	errFind := app.Db().Where("pid = ?", nc.Id).Find(&items)
	if errFind != nil {
		return nil, errFind
	}

	return items, nil
}

// 获取单个数据
// @param id int64 数据的id
// @return *Nodes, error
func GetItemById(id int64) (*NodeCategory, error) {
	node := new(NodeCategory)
	has, err := app.Db().Where("id = ?", id).Get(node)

	if err != nil {
		return nil, err
	}

	if !has {
		return nil, app.NewError("对不起, 目标不存在")
	}

	return node, nil
}

// 获取用户所有的分类数据
// @return map[int64] *NodeCategory, error
func GetAllItemsFromDb() ([]*NodeCategory, error) {
	category := make([]*NodeCategory, 0)
	err := app.Db().Where("status = ?", true).Asc("sort").Find(&category)
	if err != nil {
		return nil, err
	}
	return category, nil
}

// 后去所有的编辑用户
// @param id int64 数据的id
// @return *Nodes, error
func GetEditorSelectOption() ([]map[string]interface{}, error) {
	allEditor, errGet := users.GetAllEditorFromCache()
	if errGet != nil {
		return nil, errGet
	}

	data := make([]map[string]interface{}, 0)
	for userId, user := range allEditor {
		data = append(data, map[string]interface{}{
			"label": user.Nickname,
			"value": userId,
		})
	}

	return data, nil
}

// 获取所有的分类选项
func GetCategoryOptions() ([]*CategorySelectData, error) {
	allCategory, errCache := GetAllItemsFromCache()
	if errCache != nil {
		return nil, app.NewError(errCache)
	}

	return BuildCategoryDataTree(allCategory, 0), nil
}

// @title BuildMenusTree
// @description 构建山下级关系树
func BuildCategoryDataTree(sourceData []*NodeCategory, pid int64) []*CategorySelectData {
	buildData := make([]*CategorySelectData, 0)

	for _, item := range sourceData {
		if item.Pid == pid {
			data := CategorySelectData{
				Id:       item.Id,
				Label:    item.Title,
				Children: make([]*CategorySelectData, 0),
			}

			data.Children = BuildCategoryDataTree(sourceData, item.Id)

			buildData = append(buildData, &data)
		}
	}

	return buildData
}

/** ============================= 帮助函数 ================================ */
// 返回的数据结构 select
type CategorySelectTree struct {
	Value    int64                 `json:"value"`
	Label    string                `json:"label"`
	Children []*CategorySelectTree `json:"children"`
}

// 给的category列表　转换成上下级的形式
func BuildCategoryTree(items map[int64]*NodeCategory, pid int64) []*CategorySelectTree {
	data := make([]*CategorySelectTree, 0)
	for itemId, item := range items {
		if item.Pid == pid {
			tmpObj := CategorySelectTree{
				Value: itemId,
				Label: item.Title,
			}
			tmpObj.Children = BuildCategoryTree(items, item.Id)
			data = append(data, &tmpObj)
		}
	}

	return data
}

// 检测字段唯一性
func IsUniqueFieldValueExist(field string, value interface{}) bool {
	user := new(NodeCategory)

	has, err := app.Db().Where(field+" = ?", value).Get(user)

	if err != nil {
		return false
	} else {
		if !has {
			return false
		}
	}

	return true
}

// @title IsEditorExist
// @description 编辑是否存在
func IsEditorExist(userId int64) bool {
	allEditor, errGet := users.GetAllEditorFromCache()
	if errGet != nil {
		return false
	}

	// 是否存在
	if _, ok := allEditor[userId]; !ok {
		return false
	}

	return true
}
